package it.chengdazhi.decentbanner;


import ohos.agp.components.*;
import ohos.agp.utils.Color;
import ohos.app.Context;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;
import ohos.eventhandler.InnerEvent;
import ohos.global.resource.NotExistException;
import ohos.media.image.ImageSource;
import ohos.media.image.PixelMap;
import ohos.media.image.common.Size;
import ohos.multimodalinput.event.MmiPoint;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

import static ohos.multimodalinput.event.TouchEvent.*;

public class DecentBanner extends DependentLayout {
    DirectionalLayout cursor;
    Image logo;
    PageSlider viewPager;
    Component gradientCover;
    private DecentBannerAdapter decentBannerAdapter;

    private static final int MESSAGE_SCROLL = 123;
    private int homeColumnScrollInterval = 4;
    private int tabNum = 0;
    private int viewNum = 0;
    private static final int ITEM_MAX_NUM = 200000;
    private static final int CURSOR_HEIGHT_DP = 2;
    private int animationDuration = 300;
    private boolean enableGradient = true;
    private Component mCurrentComponent;
    private boolean isDown = false;
    private float startX;
    private float moveX;

    private List<Text> titles;

    private EventHandler handler = new EventHandler(EventRunner.create()) {
        @Override
        protected void processEvent(InnerEvent event) {
            if (event.eventId == MESSAGE_SCROLL) {
                if(viewPager != null) {
                    isDown = false;
                    getContext().getUITaskDispatcher().asyncDispatch(() -> viewPager.setCurrentPage(viewPager.getCurrentPage() + 1));
                    startAutoPlay();
                }
            }
        }
    };
    private float TWOTYFIVE = 25F;
    private boolean isSlipRight = false; //手指滑动方向

    public void startAutoPlay() {
        stopAutoPlay();
        handler.sendEvent(MESSAGE_SCROLL, homeColumnScrollInterval * 1000);
    }

    public void stopAutoPlay() {
        handler.removeEvent(MESSAGE_SCROLL);
    }

    public DecentBanner(Context context) {
        super(context);
    }

    public DecentBanner(Context context, AttrSet attrs) {
        super(context, attrs);
    }

    public DecentBanner(Context context, AttrSet attrs, String styleName) {
        super(context, attrs, styleName);
    }

    public void start(List<Component> views, List<String> titles, int interval, int animationDuration) {
        init(views, titles, interval, animationDuration, 0);
    }

    public void start(List<Component> views, List<String> titles, int interval, int animationDuration, int logoResourceId) {
        init(views, titles, interval, animationDuration, logoResourceId);
    }

    public void start(List<Component> views, List<String> titles, int interval, int animationDuration, PixelMap logo) {
        init(views, titles, interval, animationDuration, logo);
    }

    public void setGradientEnabled(boolean enabled) {
        this.enableGradient = enabled;
        if (gradientCover != null) {
            if (enabled) {
                gradientCover.setVisibility(VISIBLE);
            } else {
                gradientCover.setVisibility(HIDE);
            }
        }
    }

    public boolean isGradientEnabled() {
        return enableGradient;
    }

    private void init(List<Component> views, final List<String> titleStrings, int interval, int animationDuration, int logoResourceId) {
        PixelMap logoBitmap = null;
        if (logoResourceId > 0) {
            InputStream is = null;
            try {
                is = getContext().getResourceManager().getResource(logoResourceId);
                ImageSource.SourceOptions sourceOptions = new ImageSource.SourceOptions();
                sourceOptions.formatHint = "image/jpg";
                ImageSource imageSource = ImageSource.create(is, sourceOptions);
                ImageSource.DecodingOptions decodingOptions = new ImageSource.DecodingOptions();
                decodingOptions.desiredSize = new Size(AttrHelper.vp2px(TWOTYFIVE, getContext()),
                        AttrHelper.vp2px(TWOTYFIVE, getContext()));
                logoBitmap = imageSource.createPixelmap(decodingOptions);
            } catch (IOException e) {
                e.printStackTrace();
            } catch (NotExistException e) {
                e.printStackTrace();
            } finally {
                if (is != null) {
                    try {
                        is.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        } else {
            logoBitmap = null;
        }
        init(views, titleStrings, interval, animationDuration, logoBitmap);
    }

    private void init(List<Component> views, final List<String> titleStrings, int interval, int animationDuration, PixelMap logoBitmap) {
        Component view = LayoutScatter.getInstance(getContext()).parse(ResourceTable.Layout_decent_banner_layout, this, true);
        cursor = (DirectionalLayout) view.findComponentById(ResourceTable.Id_cursor_view);
        logo = (Image) view.findComponentById(ResourceTable.Id_logo_image);
        viewPager = (PageSlider) view.findComponentById(ResourceTable.Id_viewpager);
        gradientCover = view.findComponentById(ResourceTable.Id_gradient_cover);

        if (enableGradient) {
            gradientCover.setVisibility(VISIBLE);
        } else {
            gradientCover.setVisibility(HIDE);
        }

        if (logoBitmap != null) {
            logo.setVisibility(VISIBLE);
            logo.setPixelMap(logoBitmap);
        } else {
            logo.setVisibility(HIDE);
        }

        this.homeColumnScrollInterval = interval;
        this.animationDuration = animationDuration;

        viewNum = views.size();
        tabNum = titleStrings.size();

        titles = new ArrayList<>(tabNum);
        for (String titleString : titleStrings) {
            Text title = new Text(getContext());
            title.setText(titleString);
            title.setTextColor(Color.WHITE);
            title.setTextSize(50);
            addComponent(title);
            titles.add(title);
        }

        this.setLayoutRefreshedListener(new LayoutRefreshedListener() {
            @Override
            public void onRefreshed(Component component) {
                if (!component.equals(mCurrentComponent)) {
                    mCurrentComponent = component;
                    initTabsAndCursorLayout(component);
                }
            }
        });

        decentBannerAdapter = new DecentBannerAdapter(ITEM_MAX_NUM, views);
        viewPager.setProvider(decentBannerAdapter);
        int index = ITEM_MAX_NUM / 2 - ITEM_MAX_NUM / 2 % viewNum;
        viewPager.setCurrentPage(index);

        try {
            Field mScroller = PageSlider.class.getDeclaredField("mScroller");
            mScroller.setAccessible(true);
            FixedSpeedScroller scroller = new FixedSpeedScroller(viewPager.getContext(), new AttrSet() {
                @Override
                public Optional<String> getStyle() {
                    return Optional.empty();
                }

                @Override
                public int getLength() {
                    return 0;
                }

                @Override
                public Optional<Attr> getAttr(int i) {
                    return Optional.empty();
                }

                @Override
                public Optional<Attr> getAttr(String s) {
                    return Optional.empty();
                }
            }, animationDuration);
            mScroller.set( viewPager, scroller);
        }catch(NoSuchFieldException e){
            e.printStackTrace();
        }catch (IllegalAccessException e){
            e.printStackTrace();
        }

        viewPager.setTouchEventListener((component, touchEvent) -> {
            MmiPoint pointerPosition;
            switch (touchEvent.getAction()) {
                case PRIMARY_POINT_DOWN:
                    isDown = true;
                    pointerPosition = touchEvent.getPointerPosition(0);
                    startX = pointerPosition.getX();
                    stopAutoPlay();
                    break;
                case POINT_MOVE:
                    pointerPosition = touchEvent.getPointerPosition(0);
                    moveX = pointerPosition.getX();
                    if (moveX > startX) {
                        isSlipRight = true;
                    } else {
                        isSlipRight = false;
                    }
                    break;
                case PRIMARY_POINT_UP:
                case CANCEL:
                    startAutoPlay();
                    break;
            }
            return true;
        });

        viewPager.setSlidingPossible(true);
        viewPager.setPageSwitchTime(1000);

        viewPager.addPageChangedListener(new PageSlider.PageChangedListener() {
            @Override
            public void onPageSliding(int i, float v, int i1) {
                if (i != 0) {
                    animateTitlesAndCursor(i, v);
                }
            }

            @Override
            public void onPageSlideStateChanged(int i) {
            }

            @Override
            public void onPageChosen(int i) {
            }
        });
        startAutoPlay();
    }

    public int toRealPosition(int position) {
        int realPosition = 0;
        if (tabNum != 0) {
            realPosition = (position - 1) % tabNum;
        }
        if (realPosition < 0) {
            realPosition += tabNum;
        }
        return realPosition;
    }

    public void animateTitlesAndCursor(int position, float positionOffSet) {
        if (tabNum <= 1) {
            return;
        }
        int cursorLeft = 0;
        int cursorRight = 0;

        if (isDown && isSlipRight) {
            position = position - 1;
            positionOffSet = 1 - positionOffSet;
        }
        for (int i = 0; i < tabNum; i++) {
            if ((position % tabNum) != i) {
                continue;
            }
            if ((position % tabNum) == tabNum - 1) {
                Text startTextView = titles.get(0);
                Text endTextView = titles.get(tabNum - 1);
                if (positionOffSet < 0.5) {
                    cursorRight = endTextView.getRight();
                    cursorLeft = endTextView.getLeft() + (int) (endTextView.getWidth() * positionOffSet * 1.5);
                } else {
                    cursorLeft = startTextView.getLeft();
                    cursorRight = startTextView.getRight() - (int) (startTextView.getWidth() * (1 - positionOffSet) * 1.5);
                }
                startTextView.setTextColor(new Color(Color.argb((int) (255 * (positionOffSet * 0.5 + 0.5)), 255, 255, 255)));
                endTextView.setTextColor(new Color(Color.argb((int) (255 * (1 - positionOffSet * 0.5)), 255, 255, 255)));
            } else {
                Text startTextView = titles.get(i);
                Text endTextView = titles.get(i + 1);
                cursorLeft = startTextView.getLeft() + (int) (positionOffSet * (endTextView.getLeft() - startTextView.getLeft()));
                cursorRight = startTextView.getRight() + (int) (positionOffSet * (endTextView.getRight() - startTextView.getRight()));
                startTextView.setTextColor(new Color(Color.argb((int) (255 * (1 - positionOffSet * 0.5)), 255, 255, 255)));
                endTextView.setTextColor(new Color(Color.argb((int) (255 * (positionOffSet * 0.5 + 0.5)), 255, 255, 255)));
            }
        }
        LayoutConfig layoutParams = new LayoutConfig(cursorRight - cursorLeft, dip2px(getContext(), CURSOR_HEIGHT_DP));
        layoutParams.setMarginLeft(cursorLeft);
        layoutParams.setMarginTop(cursor.getTop());
        cursor.setLayoutConfig(layoutParams);
    }

    private void initTabsAndCursorLayout(Component view) {
        int windowWidth = view.getWidth();
        int windowHeight = view.getHeight();
        int cursorLeft = 0;
        for (int i = 0; i < titles.size(); i++) {
            Text textView = titles.get(i);
            LayoutConfig layoutParams = new LayoutConfig(textView.getWidth(), textView.getHeight());
            layoutParams.setMarginLeft((windowWidth - 60) * (2 * i + 1) / (tabNum * 2) - textView.getWidth() / 2 + 30);
            if (i == 0) {
                cursorLeft = (windowWidth - 60) * (2 * i + 1) / (tabNum * 2) - textView.getWidth() / 2 + 30;
            }
            layoutParams.setMarginTop(windowHeight - dip2px(getContext(), 15) - textView.getHeight());
            textView.setLayoutConfig(layoutParams);
            if (i != 0) {
                textView.setTextColor(Color.GRAY);
            }
        }

        LayoutConfig layoutParams = new LayoutConfig(titles.get(0).getWidth(), dip2px(getContext(), CURSOR_HEIGHT_DP));
        layoutParams.setMarginLeft(cursorLeft);
        layoutParams.setMarginTop(windowHeight - dip2px(getContext(), 13));
        cursor.setLayoutConfig(layoutParams);
    }

    class FixedSpeedScroller extends PageSlider {
        int duration;

        public FixedSpeedScroller(Context context, int duration) {
            super(context);
            this.duration = duration;
        }

        public FixedSpeedScroller(Context context, AttrSet interpolator, int duration) {
            super(context, interpolator);
            this.duration = duration;
        }

        public FixedSpeedScroller(Context context, AttrSet interpolator, String styleName, int duration) {
            super(context, interpolator, styleName);
            this.duration = duration;
        }

    }

    public static int dip2px(Context context, float dpValue) {
        final int pxValue = (int)(context.getResourceManager().getDeviceCapability().screenDensity / 160 * dpValue);
        return pxValue;
    }
}
